Add timeout support to pyhl::Runtime with cancellable host sleep - #73
Merged
Conversation
Signed-off-by: danbugs <danilochiarlone@gmail.com>
std::thread::sleep() restarts on EINTR, so interrupt_handle.kill() could never wake a sleeping guest — the host function blocked for the full duration (up to 60s cap). Replace with a Condvar-based sleep that can be woken immediately by SleepCancel::cancel(). Signed-off-by: danbugs <danilochiarlone@gmail.com>
Signed-off-by: danbugs <danilochiarlone@gmail.com>
Signed-off-by: danbugs <danilochiarlone@gmail.com>
There was a problem hiding this comment.
Pull request overview
This PR adds timeout enforcement for pyhl::Runtime guest execution by introducing a new run_code_with_timeout() API backed by Hyperlight interrupt support, and updates the host-side __hl_sleep implementation to be cancellable so timeouts can interrupt sleeping guests.
Changes:
- Add
Runtime::run_code_with_timeout()that interrupts guest execution after a deadline and attempts to leave the runtime usable for subsequent calls. - Replace blocking
__hl_sleepwith a condition-variable-based sleep that can be cancelled via a sharedSleepCanceltoken; exposeSandbox::interrupt_handle()andSandbox::sleep_cancel()for external timeout wiring. - Add/extend tests for busy-spin kill,
time.sleepkill, fast-path execution, and post-timeout recovery; bump host crate version to0.6.0.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
host/tests/pyhl_runtime.rs |
Adds integration tests validating timeout behavior and recovery. |
host/src/pyhl.rs |
Introduces run_code_with_timeout() that spawns a watchdog thread to cancel sleep and kill the guest on deadline. |
host/src/lib.rs |
Implements SleepCancel, wires it into __hl_sleep, and exposes cancellation/interrupt handles on Sandbox. |
host/Cargo.toml |
Bumps crate version to 0.6.0. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+113
to
+114
| /// the host function returns and the execution loop can check | ||
| /// `is_cancelled()`. |
| if *guard { | ||
| return; | ||
| } | ||
| let _ = cvar.wait_timeout(guard, dur); |
Comment on lines
+362
to
+375
| match call_result { | ||
| Ok(()) => { | ||
| t.exit_code = self.sandbox.last_exit_code(); | ||
| Ok(t) | ||
| } | ||
| Err(_) if timed_out => { | ||
| // Restore so the next call starts clean. | ||
| self.sandbox.sleep_cancel.reset(); | ||
| self.sandbox.restore()?; | ||
| Err(anyhow!( | ||
| "execution timed out after {:.1}s", | ||
| timeout.as_secs_f64() | ||
| )) | ||
| } |
Signed-off-by: danbugs <danilochiarlone@gmail.com>
Contributor
There was a problem hiding this comment.
Linux Benchmarks
Details
| Benchmark suite | Current: 10f713e | Previous: ca05c5a | Ratio |
|---|---|---|---|
hello_world (median) |
20 ms |
20 ms |
1 |
pandas (median) |
110 ms |
110 ms |
1 |
density (per VM) |
7 MB |
7 MB |
1 |
snapshot (disk) |
385 MiB |
385 MiB |
1 |
This comment was automatically generated by workflow using github-action-benchmark.
- Fix doc comment on SleepCancel (no is_cancelled method exists) - Use wait_timeout_while to handle spurious condvar wakeups - Reset sleep_cancel unconditionally after timer joins to handle race where timer fires as guest call completes Signed-off-by: danbugs <danilochiarlone@gmail.com>
Signed-off-by: danbugs <danilochiarlone@gmail.com>
Contributor
There was a problem hiding this comment.
Windows Benchmarks
Details
| Benchmark suite | Current: 10f713e | Previous: ca05c5a | Ratio |
|---|---|---|---|
hello_world (median) |
262 ms |
266 ms |
0.98 |
pandas (median) |
805 ms |
817 ms |
0.99 |
density (per VM) |
6 MB |
6 MB |
1 |
snapshot (disk) |
392 MiB |
392 MiB |
1 |
This comment was automatically generated by workflow using github-action-benchmark.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
run_code_with_timeout()topyhl::Runtime— an alternative torun_code()that kills guest execution after a caller-specified deadline using Hyperlight'sInterruptHandle.run_code()remains unchanged for callers that don't need timeouts.__hl_sleephost function to be cancellable — previously usedstd::thread::sleep()which blocks the vCPU thread for up to 60s and can't be interrupted bykill()since the vCPU isn't in KVM_RUN. Replaced with a condvar-based sleep (SleepCancel) that wakes immediately when cancelled.SleepCancelandinterrupt_handle()onSandboxso consumers can wire up their own timeout logictime.sleepkill, fast code passthrough, and post-timeout recovery